<?php

namespace slinks\core\dependencyInjectionExt\compiler;

use slinks\core\DependencyInjection\Compiler\PassConfig;
use slinks\core\DependencyInjection\Definition;
use slinks\core\DependencyInjection\ContainerBuilder;
use slinks\core\DependencyInjection\Compiler\CompilerPassInterface;

/**
 * CompilerPassInterface class that will process individual definitions.
 * 
 * @author Navid Mitchell
 *
 */
abstract class AbstractDefinitionProcessingPass implements ICompilerPass {

    private $shouldIncludeFile;

    /**
     * 
     * 
     * @param boolean $shouldIncludeFile if true then if the Definition has a file set it will be included before processDefinition is called.
     */
    function __construct($shouldIncludeFile) {
        $this->shouldIncludeFile = $shouldIncludeFile;
    }

    /**
     * Allows sublcasses to check any pre-requisites prior to processing individual definitions. 
     * 
     * @param ContainerBuilder $container
     * @return Boolean true if the definition processing should occur. 
     */
    public function shouldProcessBegin(ContainerBuilder $container) {
        return true;
    }

    /**
     * 
     * @param string $id the service definition id; 
     * @param Definition $definition
     * @return true if processDefinition should be called for the given definition.
     */
    public abstract function shouldProcessDefinition($id, Definition $definition);

    /**
     * You can modify the Definition here before it is dumped to PHP code.
     * 
     * @param string $id the service definition id; 
     * @param Definition $definition
     */
    public abstract function processDefinition($id, Definition $definition);

    /**
     * This method can be overrided  by subclasses to do some additional work after all definitions have been processed. 
     * 
     * @param ContainerBuilder $container
     */
    public function postProcess(ContainerBuilder $container) {
        
    }

    /**
     * You can modify the container here before it is dumped to PHP code.
     *
     * @param ContainerBuilder $container
     * @return void
     */
    function process(ContainerBuilder $container) {

        if ($this->shouldProcessBegin($container)) {

            foreach ($container->getDefinitions() as $id => $definition) {
                if ($definition->isSynthetic()) {
                    continue;
                }

                if ($this->shouldProcessDefinition($id, $definition)) {

                    if ($this->shouldIncludeFile && null !== $definition->getFile()) {
                        require_once $definition->getFile();
                    }

                    $this->processDefinition($id, $definition);
                }
            }

            $this->postProcess($container);
        }
    }

    /**
     * @return the compiler pass type. Such as PassConfig::TYPE_BEFORE_OPTIMIZATION
     */
    public function getType() {
        return PassConfig::TYPE_BEFORE_OPTIMIZATION;
    }

}